package com.newenergy.wisehome.services;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.preference.PreferenceManager;
import android.support.annotation.Nullable;
import android.util.Log;
import android.widget.Toast;

import com.baidu.speech.EventListener;
import com.baidu.speech.EventManager;
import com.baidu.speech.EventManagerFactory;
import com.baidu.speech.asr.SpeechConstant;
import com.newenergy.wisehome.R;
import com.newenergy.wisehome.bd.RecogResult;
import com.newenergy.wisehome.bd.WakeUpResult;
import com.newenergy.wisehome.common.MyEvent;
import com.newenergy.wisehome.common.helper.LogHelper;
import com.newenergy.wisehome.common.helper.SPUtil;
import com.newenergy.wisehome.common.helper.VoiceHelper;
import com.newenergy.wisehome.common.util.NetWorkUtil;
import com.newenergy.wisehome.config.AppManager;
import com.newenergy.wisehome.config.Constants;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import static com.newenergy.wisehome.config.Constants.STATUS_CHINESE;

public class BaiDuService extends Service {

    private Context mContext;
    private AppManager mAppManager;
    private Toast mToast;
    private String mSpeechResult;

    private  boolean isOfflineEngineLoaded = true;
    private EventManager mAsr;

    protected String samplePath;
    /**
     * 字符串格式的参数
     */
    protected ArrayList<String> stringParams = new ArrayList<String>();

    /**
     * int格式的参数
     */
    protected ArrayList<String> intParams = new ArrayList<String>();

    /**
     * bool格式的参数
     */
    protected ArrayList<String> boolParams = new ArrayList<String>();
    private EventManager mWp;

    /**
     * 控制UI按钮的状态
     */
    private String langure = "cmn-Hans-CN";//默认语音为中文
    private int status = SPUtil.getInteger("LANGURE", STATUS_CHINESE);
    private boolean mSpeechEnable= SPUtil.getBool(Constants.SPEECH_ENABLE,false);

    @Override
    public void onCreate() {
        super.onCreate();
        init();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    public BaiDuService() {

    }


    private void init() {
        EventBus.getDefault().register(this);
        mAppManager = AppManager.getInstance(this);
        mContext = this;

        if (mSpeechEnable){
            if (NetWorkUtil.isNetworkAvailable(mContext)) {
                Log.e("LFX", "BaiDuService===init");
                    initBdSpeech();
            }
        }
    }

    private void initBdSpeech() {
        if (status == STATUS_CHINESE) langure = "cmn-Hans-CN";
        else if (status == Constants.STATUS_CANTONESE) langure = "yue-Hans-CN";
        else if (status == Constants.STATUS_SICHUANESE) langure = "sichuan-Hans-CN";
        else if (status == Constants.STATUS_ENGLISH) langure = "en-GB";
        initWakeUp();
        initRecog();
        startWakeUp();
    }

    /**
     * 在onCreate中调用。初始化离线识别
     */
    protected void initRecog() {
        mAsr = EventManagerFactory.create(mContext, "asr");
        if (isOfflineEngineLoaded) {
            loadOfflineEngine(fetchOfflineParams());
        }
    }


    private EventListener listener = new EventListener() {
        @Override
        public void onEvent(String name, String params, byte[]
                data, int offset, int length) {
            Log.e("QBH","执行到这里");
            if (SpeechConstant.CALLBACK_EVENT_WAKEUP_SUCCESS.equals(name)) { //识别唤醒词成功
                WakeUpResult result = WakeUpResult.parseJson(name,params);

                int errorCode = result.getErrorCode();
                if (result.hasError()) { // error不为0依旧有可能是异常情况
                    Log.e("QBH","唤醒出错1！");
                } else {
                    unRegisterWpListener();
//                    if (NetWorkUtil.isNetworkAvailable(mContext)){
                        VoiceHelper.getInstance(mContext).initMediaPlay(R.raw.nihao, new VoiceHelper.VoicePlayCallBack() {
                            @Override
                            public void playFinish() {
                                registerAsrListener();
                                startRecog();
                            }

                            @Override
                            public void playError() {
                                registerWpListener();
                                unRegisterAsrListener();
                            }
                        });

                   /* }else {
                        VoiceHelper.getInstance(mContext).initMediaPlay(R.raw.no_net, new VoiceHelper.VoicePlayCallBack() {
                            @Override
                            public void playFinish() {
                                registerWpListener();
                            }
                            @Override
                            public void playError() {
                                registerWpListener();
                            }
                        });

                    }*/

                }
            } else if (SpeechConstant.CALLBACK_EVENT_WAKEUP_ERROR.equals(name)) { // 识别唤醒词报错

                WakeUpResult result = WakeUpResult.parseJson(name, params);

                int errorCode = result.getErrorCode();
                if (result.hasError()) {
                    Log.e("QBH","唤醒出错2！"+errorCode);
                }
            } else if (SpeechConstant.CALLBACK_EVENT_WAKEUP_STOPED.equals(name)) { //关闭唤醒词

            } else if (SpeechConstant.CALLBACK_EVENT_WAKEUP_AUDIO.equals(name)) { // 音频回调

            }

        }
    };


    private EventListener listener2 = new EventListener() {

        private String[] mResults;
        private RecogResult mRecogResult;

        @Override
        public void onEvent(String name, String params, byte[]
                data, int offset, int length) {

            if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_READY)) {


            } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_PARTIAL)) {

                mRecogResult = RecogResult.parseJson(params);
                // 临时识别结果, 长语音模式需要从此消息中取出结果
                mResults = mRecogResult.getResultsRecognition();

            } else if (name.equals(SpeechConstant.CALLBACK_EVENT_ASR_FINISH)) {
                if (mRecogResult == null) {

                    VoiceHelper.getInstance(mContext).initMediaPlay(R.raw.sorry, new VoiceHelper.VoicePlayCallBack() {
                        @Override
                        public void playFinish() {
                            unRegisterAsrListener();
                            registerWpListener();
                        }

                        @Override
                        public void playError() {
                            unRegisterAsrListener();
                            registerWpListener();
                        }
                    });

                    return;
                }

                if (mRecogResult.hasError()) {
                    registerWpListener();
                    unRegisterAsrListener();
                } else {
                    mSpeechResult = mResults[0];
                    toast(mSpeechResult);
                    notifyRecogResult(mSpeechResult);
                    stopRecog();
                    registerWpListener();
                }

                mRecogResult = null;

            }

        }
    };

    private void toast(String result) {
        if (mToast == null) {
            mToast = Toast.makeText(mContext, "最终识别结果：" + result, Toast.LENGTH_SHORT);
        }
        mToast.setText(result);
        mToast.show();
    }

    /**
     * 通知识别结果
     *
     * @param result
     */
    private void notifyRecogResult(String result) {
        LogHelper.i("notifyRecogResult:result=" + result);
        mAppManager.notifySpeechResult(result);
    }


    /**
     * 开始录音，点击“开始”按钮后调用。
     */
    protected void startRecog() {
        if (mAsr==null)return;
        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mContext);
        Map<String, Object> params = fetch(sp);
        params.put(SpeechConstant.LANGUAGE, langure);
        params.put(SpeechConstant.DISABLE_PUNCTUATION, true);
        params.put(SpeechConstant.VAD_ENDPOINT_TIMEOUT,1500);
        String json = new JSONObject(params).toString();
        mAsr.send(SpeechConstant.ASR_START, json, null, 0, 0);
    }


    /**
     * 开始录音后，手动停止录音。SDK会识别在此过程中的录音。点击“停止”按钮后调用。
     */
    private void stopRecog() {
        if (mAsr != null) {
            mAsr.send(SpeechConstant.ASR_STOP, "{}", null, 0, 0);
        }
    }

    /**
     * 开始录音后，取消这次录音。SDK会取消本次识别，回到原始状态。点击“取消”按钮后调用。
     */
    private void cancelRecog() {
        if (mAsr==null)return;
        mAsr.send(SpeechConstant.ASR_CANCEL, "{}", null, 0, 0);
    }

    public void releaseRecog() {
        cancelRecog();
//        if (isOfflineEngineLoaded) {
//            mAsr.send(SpeechConstant.ASR_KWS_UNLOAD_ENGINE, null,
//                    null, 0, 0);
////            isOfflineEngineLoaded = false;
//        }
        mAsr.send(SpeechConstant.ASR_KWS_UNLOAD_ENGINE, null,
                null, 0, 0);
        mAsr.unregisterListener(listener2);
        mAsr = null;
    }

    /**
     * @param params
     */
    public void loadOfflineEngine(Map<String, Object> params) {
        String json = new JSONObject(params).toString();
        mAsr.send(SpeechConstant.ASR_KWS_LOAD_ENGINE, json, null,
                0, 0);
        isOfflineEngineLoaded = true;
        // 没有ASR_KWS_LOAD_ENGINE这个回调表试失败，如缺少第一次联网时下载的正式授权文件。
    }


    public Map<String, Object> fetch(SharedPreferences sp) {

        Map<String, Object> map = new HashMap<String, Object>();
        map.put(SpeechConstant.DECODER, 2);

        parseParamArr(sp, map);

        if (sp.getBoolean("_tips_sound", false)) { // 声音回调
            map.put(SpeechConstant.SOUND_START, R.raw
                    .bdspeech_recognition_start);
            map.put(SpeechConstant.SOUND_END, R.raw
                    .bdspeech_speech_end);
            map.put(SpeechConstant.SOUND_SUCCESS, R.raw
                    .bdspeech_recognition_success);
            map.put(SpeechConstant.SOUND_ERROR, R.raw
                    .bdspeech_recognition_error);
            map.put(SpeechConstant.SOUND_CANCEL, R.raw
                    .bdspeech_recognition_cancel);
        }

        if (sp.getBoolean("_outfile", false)) { // 保存录音文件
            map.put(SpeechConstant.OUT_FILE, samplePath + "/outfile" +
                    ".pcm");
        }

        return map;

    }

    /**
     * 根据 stringParams intParams
     * boolParams中定义的参数名称，提取SharedPreferences相关字段
     *
     * @param sp
     * @param map
     */
    private void parseParamArr(SharedPreferences sp, Map<String, Object> map) {
        for (String name : stringParams) {
            if (sp.contains(name)) {
                String tmp = sp.getString(name, "").replaceAll("," +
                        ".*", "").trim();
                if (null != tmp && !"".equals(tmp)) {
                    map.put(name, tmp);
                }
            }
        }
        for (String name : intParams) {
            if (sp.contains(name)) {
                String tmp = sp.getString(name, "").replaceAll("," +
                        ".*", "").trim();
                if (null != tmp && !"".equals(tmp)) {
                    map.put(name, Integer.parseInt(tmp));
                }
            }
        }
        for (String name : boolParams) {
            if (sp.contains(name)) {
                map.put(name, sp.getBoolean(name, false));
            }
        }
    }


    /**********************
     * 离线识别
     *******************************/
    public static Map<String, Object> fetchOfflineParams() {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put(SpeechConstant.DECODER, 2);
        map.put(SpeechConstant.ASR_OFFLINE_ENGINE_GRAMMER_FILE_PATH, "asset:///baidu_speech_grammar.bsg");
        map.putAll(fetchSlotDataParam());
        return map;
    }


    public static Map<String, Object> fetchSlotDataParam() {
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            JSONObject json = new JSONObject();
            json.put("name", new JSONArray().put("赵六").put("赵六"))
                    .put("appname", new JSONArray().put("手百").put
                            ("度秘"));
            map.put(SpeechConstant.SLOT_DATA, json);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return map;
    }

/**********************离线识别*******************************/


/**********************唤醒词*******************************/

    /**
     * 在onCreate中调用。初始化离线识别
     */
    protected void initWakeUp() {
        mWp = EventManagerFactory.create(mContext, "wp");
        mWp.registerListener(listener);
    }

    /**
     * 开始唤醒，点击“开始”按钮后调用。
     */
    protected void startWakeUp() {
        if (mWp==null)return;
        Map<String, Object> params = new HashMap<String, Object>();
        params.put(SpeechConstant.WP_WORDS_FILE, "assets:///WakeUp.bin");
        String json = new JSONObject(params).toString();
        mWp.send(SpeechConstant.WAKEUP_START, json, null, 0, 0);
    }

    /**
     * 停止唤醒，点击“开始”按钮后调用。
     */
    protected void stopWakeUp() {
        mWp.send(SpeechConstant.WAKEUP_STOP, null, null, 0, 0);
    }

    /**
     * 开始唤醒，点击“开始”按钮后调用。
     */
    protected void releaseWakeUp() {
        stopWakeUp();
        mWp.send(SpeechConstant.WAKEUP_UNLOAD_ENGINE,null,null,0,0);
        mWp.unregisterListener(listener);
        mWp = null;
    }


    /*********************** 唤醒词 *******************************/

    @Override
    public void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);
        stopForeground(true);
//        VoiceHelper.getInstance(this).release();
        /*if (mAsr!=null){
            releaseRecog();
        }

        if (mWp!=null){
            releaseWakeUp();
        }*/
        finishRecognize();

    }


    @Subscribe(threadMode = ThreadMode.MAIN)
    public void handleEvent(MyEvent event) {
        String tag = event.getTag();
        Object data = event.getData();
        switch (tag) {
            case Constants.STATUS_LANGURE:
                status=(Integer)data;
                if (status == STATUS_CHINESE) langure = "cmn-Hans-CN";
                else if (status == Constants.STATUS_CANTONESE) langure = "yue-Hans-CN";
                else if (status == Constants.STATUS_SICHUANESE) langure = "sichuan-Hans-CN";
                else if (status == Constants.STATUS_ENGLISH) langure = "en-GB";
                break;

            case Constants.NetWork.ENABLE_NET:
                if ((boolean) data){
                    if (mSpeechEnable){
                        boolean isFirstTime = SPUtil.getBool(Constants.ISFIRST_CREATE, true);
                        if (isFirstTime){
                            initBdSpeech();
                            SPUtil.put(Constants.ISFIRST_CREATE, false);
                        }

                    }
                }
                break;

            case Constants.ISWAKEUP:
                Log.e("LFX", "Constants.ISWAKEUP===" + data);
                if ((boolean) data){
                    if (mWp == null && mAsr == null) {
                        initBdSpeech();
                    }

                }else {
                   finishRecognize();
                }
                break;
        }
    }

    private void registerAsrListener() {
        if (mAsr != null) {
            mAsr.registerListener(listener2);
        }

    }


    private void unRegisterAsrListener() {
        if (mAsr != null) {
            mAsr.unregisterListener(listener2);
        }
    }

    private void registerWpListener() {
        if (mWp != null) {
            mWp.registerListener(listener);
        }
    }

    private void unRegisterWpListener() {
        if (mWp != null) {
            mWp.unregisterListener(listener);
        }
    }


    public void finishRecognize(){
        if ( mAsr!=null){
            mAsr.send(SpeechConstant.ASR_STOP, null, null, 0, 0);
            mAsr.send(SpeechConstant.ASR_CANCEL, null, null, 0, 0);
            mAsr.send(SpeechConstant.ASR_KWS_UNLOAD_ENGINE, null, null, 0, 0);
            if (listener2 !=null){
                mAsr.unregisterListener(listener2);

            }
            mAsr = null;
        }
        if ( mWp!=null) {
            mWp.send(SpeechConstant.WAKEUP_STOP, null, null, 0, 0);
            mWp.send(SpeechConstant.WAKEUP_UNLOAD_ENGINE, null, null, 0, 0);
            if (listener != null) {
                mWp.unregisterListener(listener);

            }
            mWp = null;
        }
    }

}
